package main

import (
	"flag"
	"fmt"
	"log"
	"os"
	"path/filepath"
	"sync"
	"time"

	"github.com/yourusername/taluo-crawler/crawler"
)

// 配置选项
type Config struct {
	BaseURL         string
	Categories      []string
	ResultDir       string
	Concurrency     int
	RequestInterval time.Duration
	Timeout         time.Duration
	MaxArticles     int
}

func main() {
	// 解析命令行参数
	resultDir := flag.String("output", "results", "结果保存目录")
	concurrency := flag.Int("concurrency", 2, "并发数量")
	interval := flag.Int("interval", 2, "请求间隔(秒)")
	timeout := flag.Int("timeout", 30, "请求超时时间(秒)")
	verbose := flag.Bool("verbose", false, "显示详细日志")
	category := flag.String("category", "", "只爬取指定分类，不指定则爬取所有分类")
	maxArticles := flag.Int("max", 0, "每个分类最多爬取的文章数量，0表示不限制")
	flag.Parse()

	// 程序开始时间
	startTime := time.Now()

	// 创建日志文件
	logFile, err := os.OpenFile("crawler.log", os.O_CREATE|os.O_WRONLY|os.O_APPEND, 0666)
	if err == nil {
		defer logFile.Close()
		log.SetOutput(logFile)
	}

	if *verbose {
		// 如果开启详细日志，同时输出到控制台和文件
		log.SetOutput(os.Stdout)
	}

	log.Printf("爬虫程序开始执行，时间: %v\n", startTime.Format("2006-01-02 15:04:05"))

	// 创建结果目录
	if err := os.MkdirAll(*resultDir, 0755); err != nil {
		log.Fatalf("创建结果目录失败: %v", err)
	}

	// 默认的所有分类
	allCategories := []string{
		"塔罗爱情",
		"塔罗婚姻",
		"塔罗事业",
		"塔罗学业",
		"塔罗运势",
		"塔罗健康",
		"塔罗测试",
		"星座运势",
	}

	// 如果指定了特定分类，则只爬取该分类
	selectedCategories := allCategories
	if *category != "" {
		found := false
		for _, cat := range allCategories {
			if cat == *category {
				selectedCategories = []string{*category}
				found = true
				break
			}
		}

		if !found {
			log.Fatalf("指定的分类 '%s' 不存在，可用的分类有: %v", *category, allCategories)
		}
	}

	// 爬虫配置
	config := Config{
		BaseURL:         "http://www.taluo5.com",
		Categories:      selectedCategories,
		ResultDir:       *resultDir,
		Concurrency:     *concurrency,
		RequestInterval: time.Duration(*interval) * time.Second,
		Timeout:         time.Duration(*timeout) * time.Second,
		MaxArticles:     *maxArticles,
	}

	// 使用带缓冲的通道控制并发数量
	semaphore := make(chan struct{}, config.Concurrency)
	var wg sync.WaitGroup

	// 为每个分类创建爬虫
	for _, category := range config.Categories {
		wg.Add(1)

		// 获取信号量
		semaphore <- struct{}{}

		go func(cat string) {
			defer wg.Done()
			defer func() { <-semaphore }() // 释放信号量

			crawlCategory(cat, config)
		}(category)
	}

	// 等待所有爬虫完成
	wg.Wait()
	close(semaphore)

	// 打印执行总时间
	duration := time.Since(startTime)
	fmt.Printf("所有爬虫任务完成，总耗时: %v\n", duration)
	log.Printf("爬虫程序执行完毕，总耗时: %v\n", duration)
}

// crawlCategory 爬取单个分类
func crawlCategory(category string, config Config) {
	startTime := time.Now()
	fmt.Printf("开始爬取 %s 分类...\n", category)

	// 创建爬虫实例
	c := crawler.NewCrawler(config.BaseURL, category, config.MaxArticles)

	// 设置超时时间
	c.Client.Timeout = config.Timeout

	// 开始爬取
	data, err := c.Crawl()
	if err != nil {
		log.Printf("爬取 %s 失败: %v", category, err)
		fmt.Printf("爬取 %s 失败: %v\n", category, err)
		return
	}

	// 创建结果目录（如果不存在）
	if err := os.MkdirAll(config.ResultDir, 0755); err != nil {
		log.Printf("创建目录 %s 失败: %v", config.ResultDir, err)
		return
	}

	// 保存结果
	filename := filepath.Join(config.ResultDir, category+".json")
	if err := crawler.SaveToJSON(data, filename); err != nil {
		log.Printf("保存 %s 数据失败: %v", category, err)
		return
	}

	// 保存未分割的文章到单独文件
	noSplitFilename := filepath.Join(config.ResultDir, category+"_未分割.json")
	if err := c.SaveNoSplitToJSON(noSplitFilename); err != nil {
		log.Printf("保存 %s 未分割文章数据失败: %v", category, err)
	} else {
		if len(c.NoSplitRecord) > 0 {
			fmt.Printf("已将 %d 篇未分割的文章保存到 %s\n", len(c.NoSplitRecord), noSplitFilename)
			log.Printf("已将 %d 篇未分割的文章保存到 %s", len(c.NoSplitRecord), noSplitFilename)
		}
	}

	duration := time.Since(startTime)
	fmt.Printf("成功爬取并保存 %s 分类数据到 %s，耗时: %v，文章数: %d\n",
		category, filename, duration, len(data.Articles))
	log.Printf("成功爬取 %s，文章数: %d，耗时: %v", category, len(data.Articles), duration)
}
